package org.timemanager.view;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.afree.chart.AFreeChart;
import org.afree.chart.ChartFactory;
import org.afree.chart.axis.CategoryAxis;
import org.afree.chart.axis.CategoryLabelPositions;
import org.afree.chart.axis.NumberAxis;
import org.afree.chart.plot.CategoryPlot;
import org.afree.chart.plot.PlotOrientation;
import org.afree.chart.renderer.category.BarRenderer;
import org.afree.data.category.DefaultCategoryDataset;
import org.afree.data.general.DefaultPieDataset;
import org.afree.graphics.GradientColor;
import org.afree.graphics.SolidColor;
import org.afree.graphics.geom.Font;

import android.content.Context;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;

/**
 * draw category statistic chart
 * @author Dereky
 *
 */
public class CategoryAnalyzeView extends DemoView {
	private DatabaseTool databaseTool;
	private Context _context;
	/**
	 * when touch down event occurs,then record the motion at that time.
	 * it seems that all motion during touch is referred to only one motion instance.
	 * when scrolling horizontal it means move to adjacent week to view that week's statistics.
	 */
	private MotionEvent previousMotion;
	private boolean isMove;
	public Calendar startCalendar;
	public Calendar endCalendar;
	
	/**
	 * record accumulated total time and its name.
	 */
	public static class TimeEntry{
		public String eventName;
		public long time;
	}

	public CategoryAnalyzeView(Context context, AttributeSet attrs) {
		super(context, attrs);
		_context=context;
		databaseTool=new DatabaseTool(context);
	}

	public CategoryAnalyzeView(Context context) {
		super(context);
		_context=context;
		databaseTool=new DatabaseTool(context);
	}

	public void close(){
		try{
			databaseTool.close();
		}catch (Exception e) {
			// TODO: handle exception
		}
	}
	/**
	 * obtain one weekly statistics of all events of the category.
	 * @return every event of the category occurring in this week and its total time.
	 */
	public List<Map.Entry<Integer,TimeEntry>> prepareData()
	{
		/*
		 * make sure that Monday is the first day of week,
		 * while Sunday is first by default
		 */
		startCalendar=Calendar.getInstance();
		startCalendar.setTime(CategoryAnalyzeActivity.curCalendar.getTime());
		int offsetMonday=2-startCalendar.get(Calendar.DAY_OF_WEEK);
		if(offsetMonday>0) offsetMonday-=7;
		startCalendar.set(Calendar.HOUR_OF_DAY, 0);
		startCalendar.set(Calendar.MINUTE, 0);
		startCalendar.add(Calendar.DATE, offsetMonday);
		endCalendar=Calendar.getInstance();
		endCalendar.setTime(startCalendar.getTime());
		endCalendar.add(Calendar.DAY_OF_MONTH, 7);
		
		Cursor cursor=databaseTool.getCategoryEvents(CategoryAnalyzeActivity.categoryId);
		Map<Integer, TimeEntry> map=new HashMap<Integer, CategoryAnalyzeView.TimeEntry>();
		while(cursor.moveToNext()){
			TimeEntry barValue=new TimeEntry();
			barValue.eventName=cursor.getString(1);
			barValue.time=0;
			map.put(cursor.getInt(0), barValue);
		}
//		try{
//			cursor.close();
//		}catch (Exception e) {
//			// TODO: handle exception
//		}
		
		cursor=databaseTool.getWeeklyRecords(startCalendar.getTime(), 
				endCalendar.getTime(),CategoryAnalyzeActivity.categoryId);
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		
		while(cursor.moveToNext()){
			long duration=0;
			try {
				/*
				 * restrict in one day even if a record may cross some days
				 */
				Date endDate=dateFormat.parse(cursor.getString(3));
				Date startDate=dateFormat.parse(cursor.getString(2));
				if(startDate.before(startCalendar.getTime())){
					startDate=startCalendar.getTime();
				}
				if(endDate.after(endCalendar.getTime())){
					endDate=endCalendar.getTime();
				}
				/*
				 * when start time and end time is equal,then it takes 1 minute.
				 */
				duration = (endDate.getTime()-startDate.getTime())/60000+1;
			} catch (ParseException e) {
				e.printStackTrace();
			}
			TimeEntry barValue=map.get(cursor.getInt(0));
			if(barValue==null){
				barValue=new TimeEntry();
				barValue.eventName=cursor.getString(1);
				barValue.time=duration;
				map.put(cursor.getInt(0), barValue);
			}else{
				barValue.time+=duration;
			}
		}
		try{
			cursor.close();
		}catch (Exception e) {
			// TODO: handle exception
		}
		List<Map.Entry<Integer,TimeEntry>> mapList=
				new ArrayList<Map.Entry<Integer,TimeEntry>>(map.entrySet());
		/*
		 * sort the data so that the accumulated duration is increased
		 */
		Collections.sort(mapList, new Comparator<Map.Entry<Integer,TimeEntry>>(){ 
			public int compare(Map.Entry<Integer,TimeEntry> one,Map.Entry<Integer,TimeEntry> two){ 
				return one.getValue().time>two.getValue().time?1:-1; 
			} 
		});
		return mapList;
	}
	
	public String getChartTitle(){
		SimpleDateFormat dateFormat2=new SimpleDateFormat(
				getResources().getText(R.string.daily_record_title).toString());
		endCalendar.add(Calendar.DATE, -1);
		return dateFormat2.format(startCalendar.getTime())+" -- "+
			dateFormat2.format(endCalendar.getTime());
	}
	
	/**
	 * draw bar statics chart.
	 */
	public void showBarView() {
		
		List<Map.Entry<Integer,TimeEntry>> mapList=prepareData();
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		for(Map.Entry<Integer,TimeEntry> entry:mapList){
			dataset.addValue(entry.getValue().time,
					entry.getValue().eventName+DailyAnalyzeView.showPieTime(entry.getValue().time),
					entry.getValue().eventName);
		}
		if(mapList.size()==0){
			Toast.makeText(_context, _context.getText(R.string.category_list_empty),
					Toast.LENGTH_SHORT).show();
		}
		

        AFreeChart chart = ChartFactory.createBarChart(
        		getChartTitle()+
        		getResources().getText(R.string.category_analyze_bar).toString(),  // chart title
        		getResources().getText(R.string.analyze_bar_x_axis).toString(),    // domain axis label
        		getResources().getText(R.string.analyze_bar_y_axis).toString(),    // range axis label
                dataset,                  // data
                PlotOrientation.VERTICAL, // orientation
                true,                     // include legend
                false,                     // tooltips?
                false                     // URLs?
            );
        
        // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...

        // set the background color for the chart...
        chart.setBackgroundPaintType(new SolidColor(Color.WHITE));

        // get a reference to the plot for further customisation...
        CategoryPlot plot = (CategoryPlot) chart.getPlot();

        // set the range axis to display integers only...
        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

        // disable bar outlines...
        BarRenderer renderer = (BarRenderer) plot.getRenderer();
        renderer.setDrawBarOutline(false);
        renderer.setMaximumBarWidth(0.1);
        renderer.setDefaultShadowsVisible(false);

        // set up gradient paints for series...
        GradientColor gp0 = new GradientColor(Color.BLUE, Color.rgb(0, 0, 64));
        GradientColor gp1 = new GradientColor(Color.GREEN, Color.rgb(0, 64, 0));
        GradientColor gp2 = new GradientColor(Color.RED, Color.rgb(64, 0, 0));
        renderer.setSeriesPaintType(0, gp0);
        renderer.setSeriesPaintType(1, gp1);
        renderer.setSeriesPaintType(2, gp2);

        CategoryAxis domainAxis = plot.getDomainAxis();
        domainAxis.setCategoryLabelPositions(
                CategoryLabelPositions.createUpRotationLabelPositions(
                        Math.PI / 6.0));
        // OPTIONAL CUSTOMISATION COMPLETED.
        
        setChart(chart);
	}

	/**
	 * draw pie statics chart.
	 */
	public void showPieView() {
		List<Map.Entry<Integer,TimeEntry>> mapList=prepareData();
		DefaultPieDataset dataset = new DefaultPieDataset();
		for(Map.Entry<Integer,TimeEntry> entry:mapList){
			dataset.setValue(entry.getValue().eventName+DailyAnalyzeView.showPieTime(entry.getValue().time),
					entry.getValue().time+0.01);
		}
		
		if(mapList.size()==0){
			Toast.makeText(_context, _context.getText(R.string.category_list_empty),
					Toast.LENGTH_SHORT).show();
		}
		
//        AFreeChart chart = ChartFactory.createPieChart(
//        		getChartTitle()+
//        		getResources().getText(R.string.category_analyze_pie).toString(), 	// chart title
//                dataset, 			// data
//                true, 				// include legend
//                false,
//                false);
	    
//        PiePlot plot = (PiePlot) chart.getPlot();
//        plot.setLabelFont(new Font("SansSerif", Typeface.NORMAL, 10));
//        plot.setNoDataMessage("No data available");
//        plot.setCircular(true);
//        plot.setLabelGap(0.01); 
        
		MyPiePlot plot=new MyPiePlot(dataset,true);
		plot.setLabelFont(new Font("SansSerif", Typeface.NORMAL, 10));
		plot.setNoDataMessage("No data available");
		plot.setCircular(true);
		plot.setLabelGap(0.01); 
		AFreeChart chart = new AFreeChart(getChartTitle()+
        		getResources().getText(R.string.category_analyze_pie).toString(),
        		plot);
        
        setChart(chart);
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch(ev.getAction()){
			case MotionEvent.ACTION_DOWN:
				previousMotion=MotionEvent.obtain(ev);
				isMove=false;
				break;
			case MotionEvent.ACTION_MOVE:
				isMove=true;
				break;
			case MotionEvent.ACTION_UP:
				Log.e("analyze","up");
				if(isMove && ev!=null && previousMotion!=null){
					Log.e("analyze x",(previousMotion.getRawX()-ev.getRawX())+"");
					Log.e("analyze y",(previousMotion.getRawY()-ev.getRawY())+"");
					if(Math.abs(previousMotion.getRawX()-ev.getRawX())>
						Math.abs(previousMotion.getRawY()-ev.getRawY()) && 
						Math.abs(previousMotion.getRawX()-ev.getRawX())>DailyAnalyzeView.DEFAULT_SLIDE_DISTANCE){
						if(previousMotion.getRawX()<ev.getRawX()){
							CategoryAnalyzeActivity.curCalendar.add(Calendar.DAY_OF_MONTH, -7);	
							if(CategoryAnalyzeActivity.isShowBarView){
								showBarView();
							}else{
								showPieView();
							}
						}else {
							Calendar today=Calendar.getInstance();
							int offsetMonday=2-today.get(Calendar.DAY_OF_WEEK);
							if(offsetMonday>0) offsetMonday-=7;
							today.set(Calendar.HOUR_OF_DAY, 0);
							today.set(Calendar.MINUTE, 0);
							today.set(Calendar.SECOND, 0);
							today.set(Calendar.MILLISECOND, 0);
							today.add(Calendar.DATE, offsetMonday);
							
							if(CategoryAnalyzeActivity.curCalendar.before(today)){
								/*
								 * there is no way to see tomorrow's records
								 */
								CategoryAnalyzeActivity.curCalendar.add(Calendar.DAY_OF_MONTH, 7);
							}
							if(CategoryAnalyzeActivity.isShowBarView){
								showBarView();
							}else{
								showPieView();
							}
						}
						
					}
					isMove=false;
					previousMotion=null;
					/*
					 * when it detects horizontal scroll gesture,
					 * then there is no need to pass to super to handle 
					 */
					return true;
				}
				break;
		}
		
		return true;
		//return super.onTouchEvent(ev);
	}
	
}
